# Load Library

library(data.table) # transpose
library(forecast) # base
library(ggplot2) # base
library(TSstudio) #ts_plot, ts_heatmap, ts_seasonal
library(tseries) # adf.test
library(tsutils) # BIC
library(funtimes) # notrend_test
library(flexmix) # mseastest
# Functions

my_plot.decomposed.ts = function(x, title="", ...) {
  xx <- x$x
  if (is.null(xx)) 
    xx <- with(x, if (type == "additive") 
      random + trend + seasonal
      else random * trend * seasonal)
  plot(cbind(observed = xx, trend = x$trend, seasonal = x$seasonal, random = x$random), 
       main=title, ...)
} # In order to add personal title

my_plot.lags.ts = function (ts.obj, lags = 1:12, main = "", margin = 0.02, Xshare = TRUE, 
    Yshare = TRUE, n_plots = 3) 
{
    `%>%` <- magrittr::`%>%`
    df <- df_wide <- p <- obj.name <- lag <- lag_plots <- time <- NULL
    obj.name <- base::deparse(base::substitute(ts.obj))
    if (!is.numeric(lags)) {
        warning("The 'lags' parameter is not valid, using the defualt setting (lags = 1:12)")
        lags <- 1:12
    }
    else if (base::any(lags <= 0)) {
        warning("The 'lags' parameter is not valid, using the defualt setting (lags = 1:12)")
        lags <- 1:12
    }
    else if (!all(base::round(lags) == lags)) {
        stop("Some of the inputs of the 'lags' argument are not integer type")
    }
    if (!is.numeric(margin)) {
        warning("The 'margin' parameter is not valid, using the defualt setting (margin = 0.2)")
        margin <- 0.2
    }
    if (!is.logical(Xshare)) {
        warning("The 'Xshare' parameter is not valid, please use only boolean operators.", 
            " Using the defualt setting setting (Xshare = TRUE")
        Xshare <- TRUE
    }
    if (!is.logical(Yshare)) {
        warning("The 'Yshare' parameter is not valid, please use only boolean operators.", 
            " Using the defualt setting setting (Yshare = TRUE")
        Yshare <- TRUE
    }
    if (stats::is.ts(ts.obj)) {
        if (stats::is.mts(ts.obj)) {
            warning("The 'ts.obj' has multiple columns, only the first column will be plot")
            ts.obj <- ts.obj[, 1]
        }
        df <- base::data.frame(time = stats::time(ts.obj), y = base::as.numeric(ts.obj)) %>% 
            dplyr::arrange(time)
    }
    else if (xts::is.xts(ts.obj) | zoo::is.zoo(ts.obj)) {
        if (!is.null(base::dim(ts.obj))) {
            if (base::dim(ts.obj)[2] > 1) {
                warning("The 'ts.obj' has multiple columns, only the first column will be plot")
                ts.obj <- ts.obj[, 1]
            }
        }
        df <- base::data.frame(time = zoo::index(ts.obj), y = base::as.numeric(ts.obj)) %>% 
            dplyr::arrange(time)
    }
    else {
        stop("The input object is not valid (must be 'ts', 'xts', or 'zoo')")
    }
    p_list <- lapply(base::seq_along(lags), function(i) {
        plotly::plot_ly(x = df$y %>% dplyr::lag(lags[i]), y = df$y, 
            type = "scatter", mode = "markers") %>% plotly::layout(xaxis = list(title = "", 
            range = c(base::min(stats::na.omit(df$y)), base::max(stats::na.omit(df$y)))), 
            yaxis = list(range = c(base::min(stats::na.omit(df$y)), 
                base::max(stats::na.omit(df$y)))), annotations = list(text = paste("Lag", 
                lags[i], sep = " "), xref = "paper", yref = "paper", 
                yanchor = "bottom", xanchor = "center", align = "center", 
                x = 0.5, y = 0.9, showarrow = FALSE))
    })
    p <- base::suppressWarnings(plotly::subplot(p_list, nrows = base::ceiling(base::length(p_list)/n_plots), 
        margin = margin, shareX = Xshare, shareY = Yshare) %>% 
        plotly::layout(title = main) %>% plotly::hide_legend())
    return(p)
} # In order to add personal title
# Load Data

Sales <- read.csv('/Users/lorenzoleoni/Desktop/Materiale Personale/Projects/Time Series Analysis - Car Sales In Italy/data/SalesITA.csv',
                  header = TRUE,
                  sep = ";",
                  dec = ",")

DATA PRE-PROCESSING

# Preparation of Data

t <- transpose(Sales)

names(t) <- Sales[,'Make'] # save columns names as models

t <- t[-c(1),] # drop row Make

t <- as.data.frame(lapply(t,as.integer)) # convert value into integers

row.names(t) <- names(Sales[,2:124]) # save rows names as periods

t$ITALY <- rowSums(t)
# Italy Sales Time Series

ITA <- ts(t$ITALY,
        start = c(2012, 1), 
        end = c(2022,03),
        freq = 12)

TIME SERIES ANALYSIS

# Summary Statistics

summary(ITA)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   4119  109093  133365  132127  155404  225448 
# Time Series

ts_plot(ITA,
     Xgrid = T, 
     Ygrid = T,
     Ytitle = "Units",
     Xtitle = "Year",
     title = "Time Series - Italy Sales",
     width = 2,
     color = "black")
NA
# Seasonal Italy Sales

ts_seasonal(ITA,
            type = "all",
            title = "Seasonal - Italy Sales")
NA
# Cycle and Seasonal Analysis

ts_heatmap(ITA,
           title = "Heatmap - Italy Sales")
NA
# Method of coefficient of variation of seasonal differences and quotients

i = 13
k = 0

D = vector() # Seasonal Difference
Q = vector() # Seasonal Quotient

while (k<length(ITA)-12){
  
  D[i-12] <- ITA[i]-ITA[i-12]
  Q[i-12] <- ITA[i]/ITA[i-12]
  
  i = i + 1
  k = k + 1
  
}

cv_d = sd(D)/mean(D) # coefficient of variation of the seasonal differences

cv_q = sd(Q)/mean(Q) # coefficient of variation of the seasonal quotients

dec = list()

seasonal_test <- mseastest(ITA, type = "pearson", m = 12)

if (abs(cv_q) <= abs(cv_d) & seasonal_test$is.multiplicative == T){
  print("The time series is multiplicative")
  dec = "mult"} else if (abs(cv_q) > abs(cv_d) & seasonal_test$is.multiplicative == F){
    print("The time series is additive") 
    dec = "add"} else{
      print("Tests have different results")
      }
[1] "The time series is multiplicative"
# Decomposition Time Series

ITA.dec <- decompose(ITA,
                   type = dec)

my_plot.decomposed.ts(ITA.dec, 
                      title = "Decomposition Time Series - Italy Sales",
                      cex.main = 1,
                      font.main = 1,
                      col.main = "#444444",
                      col.lab = "#444444",
                      cex.lab = 0.8,
                      cex.axis = 1,
                      xlab = "Year",
                      lwd = 2)

# Autocorrelation

ac <- acf(ITA,
          lag.max = 24,
          plot = F)

par(cex.main = 1,
    font.main = 1,
    col.main = "#444444",
    font.lab=1,
    col.lab = "#444444",
    cex.lab = 0.8,
    cex.axis = 0.8)
plot(ac, main = "")
title(main = "Autocorrelation Italy Sales")

# Partial Autocorrelation

pac <- pacf(ITA,
            lag.max = 24,
            plot = F)

par(cex.main = 1,
    font.main = 1,
    col.main = "#444444",
    font.lab=1,
    col.lab = "#444444",
    cex.lab = 0.8,
    cex.axis = 0.8)
plot(pac, main = "")
title(main = "Partial Autocorrelation Italy Sales")

# Seasonal Adjustment 

ITA_des <- diff(ITA,
              lag = 12)

ts_plot(ITA_des,
        Xgrid = T, 
        Ygrid = T,
        Xtitle = "Year",
        title = "TS Deseasonalized - Italy Sales",
        width = 2,
        color = "black")
NA
# Autocorrelation TS Deseasonalized

ac <- acf(ITA_des,
          lag.max = 24,
          plot = F)

par(cex.main = 1,
    font.main = 1,
    col.main = "#444444",
    font.lab=1,
    col.lab = "#444444",
    cex.lab = 0.8,
    cex.axis = 0.8)

plot(ac, main = "")
title(main = "TS Deseasonalized - Autocorrelation Italy Sales")

# Partial Autocorrelation TS Deseasonalized

ac <- pacf(ITA_des,
           lag.max = 24,
           plot = F)

par(cex.main = 1,
    font.main = 1,
    col.main = "#444444",
    font.lab=1,
    col.lab = "#444444",
    cex.lab = 0.8,
    cex.axis = 0.8)

plot(ac, main = "")
title(main = "TS Deseasonalized - Partial Autocorrelation Italy Sales")

# Trend Adjustment 

ITA_det <- diff(ITA,
              lag = 1)

ts_plot(ITA_det,
        Xgrid = T, 
        Ygrid = T,
        Xtitle = "Year",
        title = "TS Detrendalized - Italy Sales",
        width = 2,
        color = "black")
NA
# Autocorrelation TS Detrendalized

ac <- acf(ITA_det,
          lag.max = 24,
          plot = F)

par(cex.main = 1,
    font.main = 1,
    col.main = "#444444",
    font.lab=1,
    col.lab = "#444444",
    cex.lab = 0.8,
    cex.axis = 0.8)

plot(ac, main = "")
title(main = "TS Detrendalized - Autocorrelation Italy Sales")

# Partial Autocorrelation TS Detrendalized

ac <- pacf(ITA_det,
           lag.max = 24,
           plot = F)

par(cex.main = 1,
    font.main = 1,
    col.main = "#444444",
    font.lab=1,
    col.lab = "#444444",
    cex.lab = 0.8,
    cex.axis = 0.8)

plot(ac, main = "")
title(main = "TS Detrendalized - Partial Autocorrelation Italy Sales")

# Lag Plots

my_plot.lags.ts(ITA,
                main = "Lag Plots - Italy Sales")
NA

TIME SERIES MODEL SELECTION

HWES (Holt-Winter’s Exponential Smoothing Model)

# HWES - Auto

train.ts <- window(ITA,
                   start = c(2012,1),
                   end = c(2021,3))
test.ts <- window(ITA,
                  start = c(2021,3),
                  end = c(2022,3))

hw <- ets(train.ts,
          model = "ZZZ",
          restrict = F,
          allow.multiplicative.trend = T) # see plot seasonal in decompose

hw$method 
[1] "ETS(A,N,A)"
# Introductory Time Series With R - P. S. P. Cowperwait & A. V. Metcalfe (2009), pag 86
# Wavk Test for Trend Detection

notrend_test(train.ts,
             test = "WAVK",
             ar.method = "burg",
             ar.order = 2,
             BIC = F) 

    Sieve-bootstrap WAVK trend test

data:  train.ts
WAVK test statistic = 16.59, moving window = 11, p-value = 0.159
alternative hypothesis: (non-)monotonic trend.
sample estimates:
$AR_order
[1] 2

$AR_coefficients
      phi_1       phi_2 
0.545853992 0.000907434 
# Why Yule-Walker Should Not Be Used For Autoregressive Modelling.pdf
# funtimes.pdf, pag 25
# HWES - Additive Error

hw <- ets(train.ts,
          model = "ANM", # M seasonal how shown in previous section
          restrict = F)

hw.pred <- forecast(hw,
                    h = 12,
                    level = 0)

Train_Set <- train.ts

Test_Set <- test.ts

HW_Train <- hw$fitted

HW_Test <- ts(c(hw$fitted[111], hw.pred$mean), 
                    start = c(2021,3), 
                    end = c(2022,3), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Test_Set,HW_Train,HW_Test),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "HWES (A,N,M)",
        width = 2)
NA
# Metrics for HWES - Additive Error

print(paste("HWES Model with additive error --> AIC:",
            round(hw$aic,2),
            "BIC:",
            round(hw$bic,2),
            "AICc:",
            round(hw$aicc,2)))
[1] "HWES Model with additive error --> AIC: 2759.94 BIC: 2800.58 AICc: 2764.99"
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(hw,
               lag = 24)

    Ljung-Box test

data:  Residuals from ETS(A,N,M)
Q* = 30.464, df = 10, p-value = 0.0007189

Model df: 14.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(hw$residuals)

    Shapiro-Wilk normality test

data:  hw$residuals
W = 0.71812, p-value = 2.663e-13
# HWES - Multiplicative Error

hw <- ets(train.ts,
          model = "MNM",
          restrict = F) # see plot seasonal in decompose

hw.pred <- forecast(hw,
                    h = 12,
                    level = 0)

HW_Train <- hw$fitted

HW_Test <- ts(c(hw$fitted[111], hw.pred$mean), 
                    start = c(2021,3), 
                    end = c(2022,3), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Test_Set,HW_Train,HW_Test),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "HWES (M,N,M)",
        width = 2)
NA
# Metrics for HWES - Multiplicative Error

print(paste("HWES Model with multiplicative error --> AIC:",
            round(hw$aic,2),
            "BIC:",
            round(hw$bic,2),
            "AICc:",
            round(hw$aicc,2)))
[1] "HWES Model with multiplicative error --> AIC: 2755.71 BIC: 2796.35 AICc: 2760.76"
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(hw,
               lag = 24)

    Ljung-Box test

data:  Residuals from ETS(M,N,M)
Q* = 67.708, df = 10, p-value = 1.226e-10

Model df: 14.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(hw$residuals)

    Shapiro-Wilk normality test

data:  hw$residuals
W = 0.67974, p-value = 3.154e-14

SARIMA (Seasonal Autoregressive Integrated Moving Average)

# SARIMA Models

train.ts <- window(ITA, 
                   start = c(2012,1),
                   end = c(2021,3))
valid.ts <- window(ITA, 
                   start = c(2021,3), 
                   end = c(2021,9))
test.ts <- window(ITA, 
                  start = c(2021,9), 
                  end = c(2022,3))

sarima <- auto.arima(train.ts, 
                     seasonal = T) # (0,1,0)(2,0,0)

print(paste("Auto SARIMA Model --> AIC:",
            round(sarima$aic,2),
            "BIC:",
            round(sarima$bic,2)))
[1] "Auto SARIMA Model --> AIC: 2544.37 BIC: 2552.47"
sarima <- Arima(train.ts, 
                order = c(2,1,3), 
                seasonal = c(1,1,1))

print(paste("SARIMA Model based on theory --> AIC:",
            round(AIC(sarima),2),
            "BIC:",
            round(BIC(sarima),2)))
[1] "SARIMA Model based on theory --> AIC: 2252.2 BIC: 2272.88"
sarima <- Arima(train.ts, 
                order = c(0,1,0),
                seasonal = c(1,1,1))

print(paste("SARIMA Model near to auto.arima --> AIC:",
            round(AIC(sarima),2),
            "BIC:",
            round(BIC(sarima),2)))
[1] "SARIMA Model near to auto.arima --> AIC: 2256.41 BIC: 2264.16"
# Auto SARIMA Model

sarima <- auto.arima(train.ts, 
                     seasonal = T)

sarima.pred <- forecast(sarima,
                          h = 6,
                          level = 0)

Train_Set <- train.ts

Validation_Set <- valid.ts

Auto_SARIMA_Train <- sarima.pred$fitted

Auto_SARIMA_Validation <- ts(c(sarima.pred$fitted[111], sarima.pred$mean), 
                    start = c(2021,3), 
                    end = c(2021,9), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Validation_Set,Auto_SARIMA_Train,Auto_SARIMA_Validation),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "Auto SARIMA(0,1,0)x(2,0,0)",
        width = 2)
NA
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(sarima,
               lag = 24)

    Ljung-Box test

data:  Residuals from ARIMA(0,1,0)(2,0,0)[12]
Q* = 22.011, df = 22, p-value = 0.4593

Model df: 2.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(sarima$residuals)

    Shapiro-Wilk normality test

data:  sarima$residuals
W = 0.79083, p-value = 2.855e-11
# Scoring Auto SARIMA Model

ac <- accuracy(sarima.pred, valid.ts)

row.names(ac)[2] <- "Validation Set"

ac
                        ME     RMSE      MAE        MPE     MAPE      MASE       ACF1
Training set      599.8114 23462.75 14247.40  -4.595007 15.48494 0.7895236 -0.0542865
Validation Set -65053.2068 72025.55 65053.21 -65.816179 65.81618 3.6049414  0.2716382
               Theil's U
Training set          NA
Validation Set  2.432375
# SARIMA Model based on Theory

sarima <- Arima(train.ts, 
                order = c(2,1,3), 
                seasonal = c(1,1,1))

sarima.pred <- forecast(sarima,
                        h = 6,
                        level = 0)

Train_Set <- train.ts

Validation_Set <- valid.ts

SARIMA_Theory_Train <- sarima.pred$fitted

SARIMA_Theory_Validation <- ts(c(sarima.pred$fitted[111], sarima.pred$mean), 
                    start = c(2021,3), 
                    end = c(2021,9), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Validation_Set,SARIMA_Theory_Train,SARIMA_Theory_Validation),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "SARIMA(2,1,3)x(1,1,1)",
        width = 2)
NA
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(sarima,
               lag = 24)

    Ljung-Box test

data:  Residuals from ARIMA(2,1,3)(1,1,1)[12]
Q* = 10.566, df = 17, p-value = 0.8782

Model df: 7.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(sarima$residuals)

    Shapiro-Wilk normality test

data:  sarima$residuals
W = 0.59844, p-value = 5.915e-16
# Scoring SARIMA Model based on Theory

ac <- accuracy(sarima.pred, valid.ts)

row.names(ac)[2] <- "Validation Set"

ac
                        ME     RMSE       MAE       MPE     MAPE      MASE          ACF1
Training set      366.7765 18151.56  8995.061  -8.79325 15.26784 0.4984638 -0.0004354358
Validation Set -14139.2749 19587.28 17037.117 -13.45274 15.46243 0.9441165 -0.4827313486
               Theil's U
Training set          NA
Validation Set 0.7041307
# SARIMA Model near to Auto

sarima <- Arima(train.ts, 
                order = c(0,1,0),
                seasonal = c(1,1,1))

sarima.pred <- forecast(sarima,
                          h = 6,
                          level = 0)

Train_Set <- train.ts

Validation_Set <- valid.ts

SARIMA_Near_Train <- sarima.pred$fitted

SARIMA_Near_Validation <- ts(c(sarima.pred$fitted[111], sarima.pred$mean), 
                    start = c(2021,3), 
                    end = c(2021,9), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Validation_Set,SARIMA_Near_Train,SARIMA_Near_Validation),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "SARIMA(0,1,0)x(1,1,1)",
        width = 2)
NA
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(sarima,
               lag = 24)

    Ljung-Box test

data:  Residuals from ARIMA(0,1,0)(1,1,1)[12]
Q* = 20.262, df = 22, p-value = 0.5667

Model df: 2.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(sarima$residuals)

    Shapiro-Wilk normality test

data:  sarima$residuals
W = 0.65812, p-value = 1.027e-14
# Scoring SARIMA Model Near to Auto

ac <- accuracy(sarima.pred, valid.ts)

row.names(ac)[2] <- "Validation Set"

ac
                        ME     RMSE       MAE        MPE     MAPE     MASE       ACF1
Training set      609.2847 19638.63  9789.521  -3.439208 11.12877 0.542489 0.01234894
Validation Set -42767.0066 48579.44 43417.129 -42.306566 42.75743 2.405972 0.02946240
               Theil's U
Training set          NA
Validation Set  1.696081

SARIMAX (Seasonal Autoregressive Integrated Moving Average Exogenous)

# Load Data and MIB Time Series

MIB <- read.csv('/Users/lorenzoleoni/Desktop/Materiale Personale/Projects/Time Series Analysis - Car Sales In Italy/data/MIB_12-22.csv',
                  header = TRUE,
                  sep = ";",
                  dec = ".")

MIB <- ts(MIB$CLOSE, start = c(2012,1), frequency = 12)

ts_plot(MIB,
     Xgrid = T, 
     Ygrid = T,
     Ytitle = "Value",
     Xtitle = "Year",
     title = "Time Series - MIB",
     width = 2,
     color = "black")
NA

# SARIMAX with MIB

train.MIB <- window(MIB, 
                   start = c(2012,1),
                   end = c(2021,3))
valid.MIB <- window(MIB, 
                   start = c(2021,3), 
                   end = c(2021,9))

sarimax <- Arima(train.ts, 
                order = c(2,1,3),
                seasonal = list(order = c(1,1,1), period = 12),
                xreg=train.MIB)

sarimax.pred <- forecast(sarimax,
                          h = 6,
                          level = 0,
                          xreg=valid.MIB)

Train_Set <- train.ts

Validation_Set <- valid.ts

SARIMAX_MIB_Train <- sarimax.pred$fitted

SARIMAX_MIB_Validation <- ts(c(sarimax.pred$fitted[111], sarimax.pred$mean), 
                    start = c(2021,3), 
                    end = c(2021,9), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Validation_Set,SARIMAX_MIB_Train,SARIMAX_MIB_Validation),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "SARIMAX(2,1,3)x(1,1,1) - MIB",
        width = 2)
NA
# Metrics SARIMAX Model with MIB

print(paste("SARIMAX Model with MIB as regressor --> AIC:",
            round(AIC(sarimax),2),
            "BIC:",
            round(BIC(sarimax),2)))
[1] "SARIMAX Model with MIB as regressor --> AIC: 2243.7 BIC: 2266.96"
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(sarimax,
               lag = 24)

    Ljung-Box test

data:  Residuals from Regression with ARIMA(2,1,3)(1,1,1)[12] errors
Q* = 9.455, df = 16, p-value = 0.8935

Model df: 8.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(sarimax$residuals)

    Shapiro-Wilk normality test

data:  sarimax$residuals
W = 0.75017, p-value = 1.86e-12
# Scoring SARIMAX Model with MIB

ac <- accuracy(sarimax.pred, valid.ts)

row.names(ac)[2] <- "Validation Set"

ac
                       ME     RMSE      MAE        MPE     MAPE      MASE          ACF1
Training set     1117.204 17405.24 10165.97  -7.257166 15.35067 0.5633501  0.0003806399
Validation Set -38564.501 44762.82 40622.73 -38.013023 39.44043 2.2511200 -0.0042804871
               Theil's U
Training set          NA
Validation Set  1.577647
# Load Data and Unemployment Rate Time Series

Unr <- read.csv('/Users/lorenzoleoni/Desktop/Materiale Personale/Projects/Time Series Analysis - Car Sales In Italy/data/Unemployment_Rate_12-22.csv',
                  header = TRUE,
                  sep = ";",
                  dec = ".")

Unr <- ts(Unr$Tax, start = c(2012,1), frequency = 12)

ts_plot(Unr,
     Xgrid = T, 
     Ygrid = T,
     Ytitle = "Value",
     Xtitle = "Year",
     title = "Time Series - Unemployment Rate",
     width = 2,
     color = "black")
NA

# SARIMAX with Unemployment Rate

train.Unr <- window(Unr, 
                   start = c(2012,1),
                   end = c(2021,3))
valid.Unr <- window(Unr, 
                   start = c(2021,3), 
                   end = c(2021,9))

sarimax <- Arima(train.ts, 
                order = c(2,1,3),
                seasonal = list(order = c(1,1,1), period = 12),
                xreg=train.Unr)

sarimax.pred <- forecast(sarimax,
                          h = 6,
                          level = 0,
                          xreg=valid.Unr)

Train_Set <- train.ts

Validation_Set <- valid.ts

SARIMAX_Unr_Train <- sarimax.pred$fitted

SARIMAX_Unr_Validation <- ts(c(sarimax.pred$fitted[111], sarimax.pred$mean), 
                    start = c(2021,3), 
                    end = c(2021,9), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Validation_Set,SARIMAX_Unr_Train,SARIMAX_Unr_Validation),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "SARIMAX(2,1,3)x(1,1,1) - Unemployment Rate",
        width = 2)
NA
# Metrics SARIMAX Model with Unr

print(paste("SARIMAX Model with Unr as regressor --> AIC:",
            round(AIC(sarimax),2),
            "BIC:",
            round(BIC(sarimax),2)))
[1] "SARIMAX Model with Unr as regressor --> AIC: 2233.05 BIC: 2256.31"
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(sarimax,
               lag = 24)

    Ljung-Box test

data:  Residuals from Regression with ARIMA(2,1,3)(1,1,1)[12] errors
Q* = 14.107, df = 16, p-value = 0.5908

Model df: 8.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(sarimax$residuals)

    Shapiro-Wilk normality test

data:  sarimax$residuals
W = 0.85498, p-value = 4.905e-09
# Scoring SARIMAX Model with Unemployment Rate

ac <- accuracy(sarimax.pred, valid.ts)

row.names(ac)[2] <- "Validation Set"

ac
                       ME     RMSE      MAE        MPE     MAPE      MASE        ACF1
Training set     2101.942 15945.15 10607.78  -4.461201 13.61187 0.5878331  0.01243276
Validation Set -15993.636 19667.10 18798.90 -16.373564 18.31904 1.0417463 -0.20415951
               Theil's U
Training set          NA
Validation Set 0.5908627

TIME SERIES FORECASTING

# Train and Test Sets

train.ts <- window(ITA, 
                   start = c(2012,1),
                   end = c(2021,9))

test.ts <- window(ITA, 
                  start = c(2021,9), 
                  end = c(2022,3))
# SARIMA Model based on Theory

sarima <- Arima(train.ts, 
                order = c(2,1,3), 
                seasonal = c(1,1,1))

sarima.pred <- forecast(sarima,
                        h = 6,
                        level = 0)

Train_Set <- train.ts

Test_Set <- test.ts

SARIMA_Theory_Train <- sarima.pred$fitted

SARIMA_Theory_Test <- ts(c(sarima.pred$fitted[117], sarima.pred$mean), 
                    start = c(2021,9), 
                    end = c(2022,3), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Test_Set,SARIMA_Theory_Train,SARIMA_Theory_Test),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "SARIMA(2,1,3)x(1,1,1)",
        width = 2)
NA
# Metrics for SARIMA Model based on theory

print(paste("SARIMA Model based on theory --> AIC:",
            round(AIC(sarima),2),
            "BIC:",
            round(BIC(sarima),2)))
[1] "SARIMA Model based on theory --> AIC: 2385.19 BIC: 2406.35"
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(sarima,
               lag = 24)

    Ljung-Box test

data:  Residuals from ARIMA(2,1,3)(1,1,1)[12]
Q* = 19.666, df = 17, p-value = 0.2916

Model df: 7.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(sarima$residuals)

    Shapiro-Wilk normality test

data:  sarima$residuals
W = 0.63702, p-value = 1.37e-15
# Scoring SARIMA Model based on Theory

accuracy(sarima.pred, test.ts)
                     ME      RMSE      MAE       MPE      MAPE      MASE        ACF1
Training set   439.9404 17628.486 9329.957 -9.279028 16.367974 0.4693342 0.004670013
Test set     -4302.7059  9882.253 8604.020 -3.498895  8.143556 0.4328166 0.475375284
             Theil's U
Training set        NA
Test set     0.6970851

# SARIMAX with Unemployment Rate

train.Unr <- window(Unr, 
                   start = c(2012,1),
                   end = c(2021,9))
test.Unr <- window(Unr, 
                   start = c(2021,9), 
                   end = c(2022,2))

sarimax <- Arima(train.ts, 
                order = c(2,1,3),
                seasonal = list(order = c(1,1,1), period = 12),
                xreg=train.Unr)

sarimax.pred <- forecast(sarimax,
                          h = 6,
                          level = 0,
                          xreg=test.Unr)

SARIMAX_Unr_Train <- sarimax.pred$fitted

SARIMAX_Unr_Test <- ts(c(sarimax.pred$fitted[117], sarimax.pred$mean), 
                    start = c(2021,9), 
                    end = c(2022,3), 
                    frequency = 12)

ts_plot(cbind(Train_Set,Test_Set,SARIMAX_Unr_Train,SARIMAX_Unr_Test),
        slider = T,
        Xgrid = T, 
        Ygrid = T,
        Ytitle = "Units",
        Xtitle = "Year",
        title = "SARIMAX(2,1,3)x(1,1,1) - Unemployment Rate",
        width = 2)
NA
# Metrics SARIMAX Model with Unr

print(paste("SARIMAX Model with Unr as regressor --> AIC:",
            round(AIC(sarimax),2),
            "BIC:",
            round(BIC(sarimax),2)))
[1] "SARIMAX Model with Unr as regressor --> AIC: 2368.93 BIC: 2392.73"
# Plot Residuals and Ljung-Box Test - H0: The level of correlation between the series and its lag is equal to zero, and therefore the series observations are independent

checkresiduals(sarimax,
               lag = 24)

    Ljung-Box test

data:  Residuals from Regression with ARIMA(2,1,3)(1,1,1)[12] errors
Q* = 16.857, df = 16, p-value = 0.3949

Model df: 8.   Total lags used: 24

# Shapiro-Wilk Test - H0: Normally Distributed

shapiro.test(sarimax$residuals)

    Shapiro-Wilk normality test

data:  sarimax$residuals
W = 0.77396, p-value = 3.891e-12
# Scoring SARIMAX with Unemployment Rate

accuracy(sarimax.pred, test.ts)
                    ME      RMSE      MAE       MPE      MAPE      MASE         ACF1
Training set  1920.983 16486.468 10250.30 -4.861421 13.522537 0.5156313 -0.015423834
Test set     -4809.261  6780.918  6551.21 -4.811418  6.447388 0.3295521  0.002396678
             Theil's U
Training set        NA
Test set     0.4666134
# Delete last variables

rm(seasonal_test,
   cv_d,
   cv_q,
   MIB,
   Test_Set,
   test.ts,
   Train_Set,
   train.ts,
   valid.ts,
   Validation_Set,
   ITA.dec,
   t,
   SARIMAX_Unr_Train,
   SARIMAX_Unr_Test,
   train.Unr,
   test.Unr,
   valid.Unr,
   SARIMA_Theory_Train,
   SARIMA_Theory_Validation,
   SARIMA_Theory_Test,
   SARIMAX_Unr_Validation,
   SARIMAX_MIB_Train,
   SARIMAX_MIB_Validation,
   train.MIB,
   valid.MIB,
   Auto_SARIMA_Train,
   Auto_SARIMA_Validation,
   SARIMA_Near_Train,
   SARIMA_Near_Validation,
   hw,
   hw.pred,
   HW_Train,
   HW_Test,
   ac,
   i,
   k,
   D,
   Q,
   pac,
   my_plot.decomposed.ts,
   my_plot.lags.ts,
   ITA_det,
   ITA_des)
LS0tCnRpdGxlOiAnVGltZSBTZXJpZXMgQW5hbHlzaXM6IENhciBTYWxlcyBJbiBJdGFseScKYXV0aG9yOiAiTG9yZW56byBMZW9uaSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgpgYGB7cn0KIyBMb2FkIExpYnJhcnkKCmxpYnJhcnkoZGF0YS50YWJsZSkgIyB0cmFuc3Bvc2UKbGlicmFyeShmb3JlY2FzdCkgIyBiYXNlCmxpYnJhcnkoZ2dwbG90MikgIyBiYXNlCmxpYnJhcnkoVFNzdHVkaW8pICN0c19wbG90LCB0c19oZWF0bWFwLCB0c19zZWFzb25hbApsaWJyYXJ5KHRzZXJpZXMpICMgYWRmLnRlc3QKbGlicmFyeSh0c3V0aWxzKSAjIEJJQwpsaWJyYXJ5KGZ1bnRpbWVzKSAjIG5vdHJlbmRfdGVzdApsaWJyYXJ5KGZsZXhtaXgpICMgbXNlYXN0ZXN0CgpgYGAKCmBgYHtyfQojIEZ1bmN0aW9ucwoKbXlfcGxvdC5kZWNvbXBvc2VkLnRzID0gZnVuY3Rpb24oeCwgdGl0bGU9IiIsIC4uLikgewogIHh4IDwtIHgkeAogIGlmIChpcy5udWxsKHh4KSkgCiAgICB4eCA8LSB3aXRoKHgsIGlmICh0eXBlID09ICJhZGRpdGl2ZSIpIAogICAgICByYW5kb20gKyB0cmVuZCArIHNlYXNvbmFsCiAgICAgIGVsc2UgcmFuZG9tICogdHJlbmQgKiBzZWFzb25hbCkKICBwbG90KGNiaW5kKG9ic2VydmVkID0geHgsIHRyZW5kID0geCR0cmVuZCwgc2Vhc29uYWwgPSB4JHNlYXNvbmFsLCByYW5kb20gPSB4JHJhbmRvbSksIAogICAgICAgbWFpbj10aXRsZSwgLi4uKQp9ICMgSW4gb3JkZXIgdG8gYWRkIHBlcnNvbmFsIHRpdGxlCgpteV9wbG90LmxhZ3MudHMgPSBmdW5jdGlvbiAodHMub2JqLCBsYWdzID0gMToxMiwgbWFpbiA9ICIiLCBtYXJnaW4gPSAwLjAyLCBYc2hhcmUgPSBUUlVFLCAKICAgIFlzaGFyZSA9IFRSVUUsIG5fcGxvdHMgPSAzKSAKewogICAgYCU+JWAgPC0gbWFncml0dHI6OmAlPiVgCiAgICBkZiA8LSBkZl93aWRlIDwtIHAgPC0gb2JqLm5hbWUgPC0gbGFnIDwtIGxhZ19wbG90cyA8LSB0aW1lIDwtIE5VTEwKICAgIG9iai5uYW1lIDwtIGJhc2U6OmRlcGFyc2UoYmFzZTo6c3Vic3RpdHV0ZSh0cy5vYmopKQogICAgaWYgKCFpcy5udW1lcmljKGxhZ3MpKSB7CiAgICAgICAgd2FybmluZygiVGhlICdsYWdzJyBwYXJhbWV0ZXIgaXMgbm90IHZhbGlkLCB1c2luZyB0aGUgZGVmdWFsdCBzZXR0aW5nIChsYWdzID0gMToxMikiKQogICAgICAgIGxhZ3MgPC0gMToxMgogICAgfQogICAgZWxzZSBpZiAoYmFzZTo6YW55KGxhZ3MgPD0gMCkpIHsKICAgICAgICB3YXJuaW5nKCJUaGUgJ2xhZ3MnIHBhcmFtZXRlciBpcyBub3QgdmFsaWQsIHVzaW5nIHRoZSBkZWZ1YWx0IHNldHRpbmcgKGxhZ3MgPSAxOjEyKSIpCiAgICAgICAgbGFncyA8LSAxOjEyCiAgICB9CiAgICBlbHNlIGlmICghYWxsKGJhc2U6OnJvdW5kKGxhZ3MpID09IGxhZ3MpKSB7CiAgICAgICAgc3RvcCgiU29tZSBvZiB0aGUgaW5wdXRzIG9mIHRoZSAnbGFncycgYXJndW1lbnQgYXJlIG5vdCBpbnRlZ2VyIHR5cGUiKQogICAgfQogICAgaWYgKCFpcy5udW1lcmljKG1hcmdpbikpIHsKICAgICAgICB3YXJuaW5nKCJUaGUgJ21hcmdpbicgcGFyYW1ldGVyIGlzIG5vdCB2YWxpZCwgdXNpbmcgdGhlIGRlZnVhbHQgc2V0dGluZyAobWFyZ2luID0gMC4yKSIpCiAgICAgICAgbWFyZ2luIDwtIDAuMgogICAgfQogICAgaWYgKCFpcy5sb2dpY2FsKFhzaGFyZSkpIHsKICAgICAgICB3YXJuaW5nKCJUaGUgJ1hzaGFyZScgcGFyYW1ldGVyIGlzIG5vdCB2YWxpZCwgcGxlYXNlIHVzZSBvbmx5IGJvb2xlYW4gb3BlcmF0b3JzLiIsIAogICAgICAgICAgICAiIFVzaW5nIHRoZSBkZWZ1YWx0IHNldHRpbmcgc2V0dGluZyAoWHNoYXJlID0gVFJVRSIpCiAgICAgICAgWHNoYXJlIDwtIFRSVUUKICAgIH0KICAgIGlmICghaXMubG9naWNhbChZc2hhcmUpKSB7CiAgICAgICAgd2FybmluZygiVGhlICdZc2hhcmUnIHBhcmFtZXRlciBpcyBub3QgdmFsaWQsIHBsZWFzZSB1c2Ugb25seSBib29sZWFuIG9wZXJhdG9ycy4iLCAKICAgICAgICAgICAgIiBVc2luZyB0aGUgZGVmdWFsdCBzZXR0aW5nIHNldHRpbmcgKFlzaGFyZSA9IFRSVUUiKQogICAgICAgIFlzaGFyZSA8LSBUUlVFCiAgICB9CiAgICBpZiAoc3RhdHM6OmlzLnRzKHRzLm9iaikpIHsKICAgICAgICBpZiAoc3RhdHM6OmlzLm10cyh0cy5vYmopKSB7CiAgICAgICAgICAgIHdhcm5pbmcoIlRoZSAndHMub2JqJyBoYXMgbXVsdGlwbGUgY29sdW1ucywgb25seSB0aGUgZmlyc3QgY29sdW1uIHdpbGwgYmUgcGxvdCIpCiAgICAgICAgICAgIHRzLm9iaiA8LSB0cy5vYmpbLCAxXQogICAgICAgIH0KICAgICAgICBkZiA8LSBiYXNlOjpkYXRhLmZyYW1lKHRpbWUgPSBzdGF0czo6dGltZSh0cy5vYmopLCB5ID0gYmFzZTo6YXMubnVtZXJpYyh0cy5vYmopKSAlPiUgCiAgICAgICAgICAgIGRwbHlyOjphcnJhbmdlKHRpbWUpCiAgICB9CiAgICBlbHNlIGlmICh4dHM6OmlzLnh0cyh0cy5vYmopIHwgem9vOjppcy56b28odHMub2JqKSkgewogICAgICAgIGlmICghaXMubnVsbChiYXNlOjpkaW0odHMub2JqKSkpIHsKICAgICAgICAgICAgaWYgKGJhc2U6OmRpbSh0cy5vYmopWzJdID4gMSkgewogICAgICAgICAgICAgICAgd2FybmluZygiVGhlICd0cy5vYmonIGhhcyBtdWx0aXBsZSBjb2x1bW5zLCBvbmx5IHRoZSBmaXJzdCBjb2x1bW4gd2lsbCBiZSBwbG90IikKICAgICAgICAgICAgICAgIHRzLm9iaiA8LSB0cy5vYmpbLCAxXQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGRmIDwtIGJhc2U6OmRhdGEuZnJhbWUodGltZSA9IHpvbzo6aW5kZXgodHMub2JqKSwgeSA9IGJhc2U6OmFzLm51bWVyaWModHMub2JqKSkgJT4lIAogICAgICAgICAgICBkcGx5cjo6YXJyYW5nZSh0aW1lKQogICAgfQogICAgZWxzZSB7CiAgICAgICAgc3RvcCgiVGhlIGlucHV0IG9iamVjdCBpcyBub3QgdmFsaWQgKG11c3QgYmUgJ3RzJywgJ3h0cycsIG9yICd6b28nKSIpCiAgICB9CiAgICBwX2xpc3QgPC0gbGFwcGx5KGJhc2U6OnNlcV9hbG9uZyhsYWdzKSwgZnVuY3Rpb24oaSkgewogICAgICAgIHBsb3RseTo6cGxvdF9seSh4ID0gZGYkeSAlPiUgZHBseXI6OmxhZyhsYWdzW2ldKSwgeSA9IGRmJHksIAogICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKSAlPiUgcGxvdGx5OjpsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIiIsIAogICAgICAgICAgICByYW5nZSA9IGMoYmFzZTo6bWluKHN0YXRzOjpuYS5vbWl0KGRmJHkpKSwgYmFzZTo6bWF4KHN0YXRzOjpuYS5vbWl0KGRmJHkpKSkpLCAKICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHJhbmdlID0gYyhiYXNlOjptaW4oc3RhdHM6Om5hLm9taXQoZGYkeSkpLCAKICAgICAgICAgICAgICAgIGJhc2U6Om1heChzdGF0czo6bmEub21pdChkZiR5KSkpKSwgYW5ub3RhdGlvbnMgPSBsaXN0KHRleHQgPSBwYXN0ZSgiTGFnIiwgCiAgICAgICAgICAgICAgICBsYWdzW2ldLCBzZXAgPSAiICIpLCB4cmVmID0gInBhcGVyIiwgeXJlZiA9ICJwYXBlciIsIAogICAgICAgICAgICAgICAgeWFuY2hvciA9ICJib3R0b20iLCB4YW5jaG9yID0gImNlbnRlciIsIGFsaWduID0gImNlbnRlciIsIAogICAgICAgICAgICAgICAgeCA9IDAuNSwgeSA9IDAuOSwgc2hvd2Fycm93ID0gRkFMU0UpKQogICAgfSkKICAgIHAgPC0gYmFzZTo6c3VwcHJlc3NXYXJuaW5ncyhwbG90bHk6OnN1YnBsb3QocF9saXN0LCBucm93cyA9IGJhc2U6OmNlaWxpbmcoYmFzZTo6bGVuZ3RoKHBfbGlzdCkvbl9wbG90cyksIAogICAgICAgIG1hcmdpbiA9IG1hcmdpbiwgc2hhcmVYID0gWHNoYXJlLCBzaGFyZVkgPSBZc2hhcmUpICU+JSAKICAgICAgICBwbG90bHk6OmxheW91dCh0aXRsZSA9IG1haW4pICU+JSBwbG90bHk6OmhpZGVfbGVnZW5kKCkpCiAgICByZXR1cm4ocCkKfSAjIEluIG9yZGVyIHRvIGFkZCBwZXJzb25hbCB0aXRsZQoKCmBgYAoKCmBgYHtyfQojIExvYWQgRGF0YQoKU2FsZXMgPC0gcmVhZC5jc3YoJy9Vc2Vycy9sb3JlbnpvbGVvbmkvRGVza3RvcC9NYXRlcmlhbGUgUGVyc29uYWxlL1Byb2plY3RzL1RpbWUgU2VyaWVzIEFuYWx5c2lzIC0gQ2FyIFNhbGVzIEluIEl0YWx5L2RhdGEvU2FsZXNJVEEuY3N2JywKICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgc2VwID0gIjsiLAogICAgICAgICAgICAgICAgICBkZWMgPSAiLCIpCgpgYGAKCiMjIERBVEEgUFJFLVBST0NFU1NJTkcKCmBgYHtyfQojIFByZXBhcmF0aW9uIG9mIERhdGEKCnQgPC0gdHJhbnNwb3NlKFNhbGVzKQoKbmFtZXModCkgPC0gU2FsZXNbLCdNYWtlJ10gIyBzYXZlIGNvbHVtbnMgbmFtZXMgYXMgbW9kZWxzCgp0IDwtIHRbLWMoMSksXSAjIGRyb3Agcm93IE1ha2UKCnQgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkodCxhcy5pbnRlZ2VyKSkgIyBjb252ZXJ0IHZhbHVlIGludG8gaW50ZWdlcnMKCnJvdy5uYW1lcyh0KSA8LSBuYW1lcyhTYWxlc1ssMjoxMjRdKSAjIHNhdmUgcm93cyBuYW1lcyBhcyBwZXJpb2RzCgp0JElUQUxZIDwtIHJvd1N1bXModCkKCmBgYAoKYGBge3J9CiMgSXRhbHkgU2FsZXMgVGltZSBTZXJpZXMKCklUQSA8LSB0cyh0JElUQUxZLAogICAgICAgIHN0YXJ0ID0gYygyMDEyLCAxKSwgCiAgICAgICAgZW5kID0gYygyMDIyLDAzKSwKICAgICAgICBmcmVxID0gMTIpCmBgYAoKIyMgVElNRSBTRVJJRVMgQU5BTFlTSVMKCmBgYHtyfQojIFN1bW1hcnkgU3RhdGlzdGljcwoKc3VtbWFyeShJVEEpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNX0KIyBUaW1lIFNlcmllcwoKdHNfcGxvdChJVEEsCiAgICAgWGdyaWQgPSBULCAKICAgICBZZ3JpZCA9IFQsCiAgICAgWXRpdGxlID0gIlVuaXRzIiwKICAgICBYdGl0bGUgPSAiWWVhciIsCiAgICAgdGl0bGUgPSAiVGltZSBTZXJpZXMgLSBJdGFseSBTYWxlcyIsCiAgICAgd2lkdGggPSAyLAogICAgIGNvbG9yID0gImJsYWNrIikKCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4fQojIFNlYXNvbmFsIEl0YWx5IFNhbGVzCgp0c19zZWFzb25hbChJVEEsCiAgICAgICAgICAgIHR5cGUgPSAiYWxsIiwKICAgICAgICAgICAgdGl0bGUgPSAiU2Vhc29uYWwgLSBJdGFseSBTYWxlcyIpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gN30KIyBDeWNsZSBhbmQgU2Vhc29uYWwgQW5hbHlzaXMKCnRzX2hlYXRtYXAoSVRBLAogICAgICAgICAgIHRpdGxlID0gIkhlYXRtYXAgLSBJdGFseSBTYWxlcyIpCgpgYGAKCmBgYHtyfQojIE1ldGhvZCBvZiBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gb2Ygc2Vhc29uYWwgZGlmZmVyZW5jZXMgYW5kIHF1b3RpZW50cwoKaSA9IDEzCmsgPSAwCgpEID0gdmVjdG9yKCkgIyBTZWFzb25hbCBEaWZmZXJlbmNlClEgPSB2ZWN0b3IoKSAjIFNlYXNvbmFsIFF1b3RpZW50Cgp3aGlsZSAoazxsZW5ndGgoSVRBKS0xMil7CiAgCiAgRFtpLTEyXSA8LSBJVEFbaV0tSVRBW2ktMTJdCiAgUVtpLTEyXSA8LSBJVEFbaV0vSVRBW2ktMTJdCiAgCiAgaSA9IGkgKyAxCiAgayA9IGsgKyAxCiAgCn0KCmN2X2QgPSBzZChEKS9tZWFuKEQpICMgY29lZmZpY2llbnQgb2YgdmFyaWF0aW9uIG9mIHRoZSBzZWFzb25hbCBkaWZmZXJlbmNlcwoKY3ZfcSA9IHNkKFEpL21lYW4oUSkgIyBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gb2YgdGhlIHNlYXNvbmFsIHF1b3RpZW50cwoKZGVjID0gbGlzdCgpCgpzZWFzb25hbF90ZXN0IDwtIG1zZWFzdGVzdChJVEEsIHR5cGUgPSAicGVhcnNvbiIsIG0gPSAxMikKCmlmIChhYnMoY3ZfcSkgPD0gYWJzKGN2X2QpICYgc2Vhc29uYWxfdGVzdCRpcy5tdWx0aXBsaWNhdGl2ZSA9PSBUKXsKICBwcmludCgiVGhlIHRpbWUgc2VyaWVzIGlzIG11bHRpcGxpY2F0aXZlIikKICBkZWMgPSAibXVsdCJ9IGVsc2UgaWYgKGFicyhjdl9xKSA+IGFicyhjdl9kKSAmIHNlYXNvbmFsX3Rlc3QkaXMubXVsdGlwbGljYXRpdmUgPT0gRil7CiAgICBwcmludCgiVGhlIHRpbWUgc2VyaWVzIGlzIGFkZGl0aXZlIikgCiAgICBkZWMgPSAiYWRkIn0gZWxzZXsKICAgICAgcHJpbnQoIlRlc3RzIGhhdmUgZGlmZmVyZW50IHJlc3VsdHMiKQogICAgICB9CgpgYGAKCgpgYGB7cn0KIyBEZWNvbXBvc2l0aW9uIFRpbWUgU2VyaWVzCgpJVEEuZGVjIDwtIGRlY29tcG9zZShJVEEsCiAgICAgICAgICAgICAgICAgICB0eXBlID0gZGVjKQoKbXlfcGxvdC5kZWNvbXBvc2VkLnRzKElUQS5kZWMsIAogICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiRGVjb21wb3NpdGlvbiBUaW1lIFNlcmllcyAtIEl0YWx5IFNhbGVzIiwKICAgICAgICAgICAgICAgICAgICAgIGNleC5tYWluID0gMSwKICAgICAgICAgICAgICAgICAgICAgIGZvbnQubWFpbiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICBjb2wubWFpbiA9ICIjNDQ0NDQ0IiwKICAgICAgICAgICAgICAgICAgICAgIGNvbC5sYWIgPSAiIzQ0NDQ0NCIsCiAgICAgICAgICAgICAgICAgICAgICBjZXgubGFiID0gMC44LAogICAgICAgICAgICAgICAgICAgICAgY2V4LmF4aXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJZZWFyIiwKICAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IDIpCgpgYGAKCmBgYHtyfQojIEF1dG9jb3JyZWxhdGlvbgoKYWMgPC0gYWNmKElUQSwKICAgICAgICAgIGxhZy5tYXggPSAyNCwKICAgICAgICAgIHBsb3QgPSBGKQoKcGFyKGNleC5tYWluID0gMSwKICAgIGZvbnQubWFpbiA9IDEsCiAgICBjb2wubWFpbiA9ICIjNDQ0NDQ0IiwKICAgIGZvbnQubGFiPTEsCiAgICBjb2wubGFiID0gIiM0NDQ0NDQiLAogICAgY2V4LmxhYiA9IDAuOCwKICAgIGNleC5heGlzID0gMC44KQpwbG90KGFjLCBtYWluID0gIiIpCnRpdGxlKG1haW4gPSAiQXV0b2NvcnJlbGF0aW9uIEl0YWx5IFNhbGVzIikKCmBgYAoKYGBge3J9CiMgUGFydGlhbCBBdXRvY29ycmVsYXRpb24KCnBhYyA8LSBwYWNmKElUQSwKICAgICAgICAgICAgbGFnLm1heCA9IDI0LAogICAgICAgICAgICBwbG90ID0gRikKCnBhcihjZXgubWFpbiA9IDEsCiAgICBmb250Lm1haW4gPSAxLAogICAgY29sLm1haW4gPSAiIzQ0NDQ0NCIsCiAgICBmb250LmxhYj0xLAogICAgY29sLmxhYiA9ICIjNDQ0NDQ0IiwKICAgIGNleC5sYWIgPSAwLjgsCiAgICBjZXguYXhpcyA9IDAuOCkKcGxvdChwYWMsIG1haW4gPSAiIikKdGl0bGUobWFpbiA9ICJQYXJ0aWFsIEF1dG9jb3JyZWxhdGlvbiBJdGFseSBTYWxlcyIpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNX0KIyBTZWFzb25hbCBBZGp1c3RtZW50IAoKSVRBX2RlcyA8LSBkaWZmKElUQSwKICAgICAgICAgICAgICBsYWcgPSAxMikKCnRzX3Bsb3QoSVRBX2RlcywKICAgICAgICBYZ3JpZCA9IFQsIAogICAgICAgIFlncmlkID0gVCwKICAgICAgICBYdGl0bGUgPSAiWWVhciIsCiAgICAgICAgdGl0bGUgPSAiVFMgRGVzZWFzb25hbGl6ZWQgLSBJdGFseSBTYWxlcyIsCiAgICAgICAgd2lkdGggPSAyLAogICAgICAgIGNvbG9yID0gImJsYWNrIikKCmBgYAoKYGBge3J9CiMgQXV0b2NvcnJlbGF0aW9uIFRTIERlc2Vhc29uYWxpemVkCgphYyA8LSBhY2YoSVRBX2RlcywKICAgICAgICAgIGxhZy5tYXggPSAyNCwKICAgICAgICAgIHBsb3QgPSBGKQoKcGFyKGNleC5tYWluID0gMSwKICAgIGZvbnQubWFpbiA9IDEsCiAgICBjb2wubWFpbiA9ICIjNDQ0NDQ0IiwKICAgIGZvbnQubGFiPTEsCiAgICBjb2wubGFiID0gIiM0NDQ0NDQiLAogICAgY2V4LmxhYiA9IDAuOCwKICAgIGNleC5heGlzID0gMC44KQoKcGxvdChhYywgbWFpbiA9ICIiKQp0aXRsZShtYWluID0gIlRTIERlc2Vhc29uYWxpemVkIC0gQXV0b2NvcnJlbGF0aW9uIEl0YWx5IFNhbGVzIikKCmBgYAoKYGBge3J9CiMgUGFydGlhbCBBdXRvY29ycmVsYXRpb24gVFMgRGVzZWFzb25hbGl6ZWQKCmFjIDwtIHBhY2YoSVRBX2RlcywKICAgICAgICAgICBsYWcubWF4ID0gMjQsCiAgICAgICAgICAgcGxvdCA9IEYpCgpwYXIoY2V4Lm1haW4gPSAxLAogICAgZm9udC5tYWluID0gMSwKICAgIGNvbC5tYWluID0gIiM0NDQ0NDQiLAogICAgZm9udC5sYWI9MSwKICAgIGNvbC5sYWIgPSAiIzQ0NDQ0NCIsCiAgICBjZXgubGFiID0gMC44LAogICAgY2V4LmF4aXMgPSAwLjgpCgpwbG90KGFjLCBtYWluID0gIiIpCnRpdGxlKG1haW4gPSAiVFMgRGVzZWFzb25hbGl6ZWQgLSBQYXJ0aWFsIEF1dG9jb3JyZWxhdGlvbiBJdGFseSBTYWxlcyIpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNX0KIyBUcmVuZCBBZGp1c3RtZW50IAoKSVRBX2RldCA8LSBkaWZmKElUQSwKICAgICAgICAgICAgICBsYWcgPSAxKQoKdHNfcGxvdChJVEFfZGV0LAogICAgICAgIFhncmlkID0gVCwgCiAgICAgICAgWWdyaWQgPSBULAogICAgICAgIFh0aXRsZSA9ICJZZWFyIiwKICAgICAgICB0aXRsZSA9ICJUUyBEZXRyZW5kYWxpemVkIC0gSXRhbHkgU2FsZXMiLAogICAgICAgIHdpZHRoID0gMiwKICAgICAgICBjb2xvciA9ICJibGFjayIpCgpgYGAKCmBgYHtyfQojIEF1dG9jb3JyZWxhdGlvbiBUUyBEZXRyZW5kYWxpemVkCgphYyA8LSBhY2YoSVRBX2RldCwKICAgICAgICAgIGxhZy5tYXggPSAyNCwKICAgICAgICAgIHBsb3QgPSBGKQoKcGFyKGNleC5tYWluID0gMSwKICAgIGZvbnQubWFpbiA9IDEsCiAgICBjb2wubWFpbiA9ICIjNDQ0NDQ0IiwKICAgIGZvbnQubGFiPTEsCiAgICBjb2wubGFiID0gIiM0NDQ0NDQiLAogICAgY2V4LmxhYiA9IDAuOCwKICAgIGNleC5heGlzID0gMC44KQoKcGxvdChhYywgbWFpbiA9ICIiKQp0aXRsZShtYWluID0gIlRTIERldHJlbmRhbGl6ZWQgLSBBdXRvY29ycmVsYXRpb24gSXRhbHkgU2FsZXMiKQoKYGBgCgpgYGB7cn0KIyBQYXJ0aWFsIEF1dG9jb3JyZWxhdGlvbiBUUyBEZXRyZW5kYWxpemVkCgphYyA8LSBwYWNmKElUQV9kZXQsCiAgICAgICAgICAgbGFnLm1heCA9IDI0LAogICAgICAgICAgIHBsb3QgPSBGKQoKcGFyKGNleC5tYWluID0gMSwKICAgIGZvbnQubWFpbiA9IDEsCiAgICBjb2wubWFpbiA9ICIjNDQ0NDQ0IiwKICAgIGZvbnQubGFiPTEsCiAgICBjb2wubGFiID0gIiM0NDQ0NDQiLAogICAgY2V4LmxhYiA9IDAuOCwKICAgIGNleC5heGlzID0gMC44KQoKcGxvdChhYywgbWFpbiA9ICIiKQp0aXRsZShtYWluID0gIlRTIERldHJlbmRhbGl6ZWQgLSBQYXJ0aWFsIEF1dG9jb3JyZWxhdGlvbiBJdGFseSBTYWxlcyIpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gN30KIyBMYWcgUGxvdHMKCm15X3Bsb3QubGFncy50cyhJVEEsCiAgICAgICAgICAgICAgICBtYWluID0gIkxhZyBQbG90cyAtIEl0YWx5IFNhbGVzIikKCmBgYAoKIyMgVElNRSBTRVJJRVMgTU9ERUwgU0VMRUNUSU9OCgojIyMjIEhXRVMgKEhvbHQtV2ludGVy4oCZcyBFeHBvbmVudGlhbCBTbW9vdGhpbmcgTW9kZWwpCgpgYGB7cn0KIyBIV0VTIC0gQXV0bwoKdHJhaW4udHMgPC0gd2luZG93KElUQSwKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDEyLDEpLAogICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDMpKQp0ZXN0LnRzIDwtIHdpbmRvdyhJVEEsCiAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDIxLDMpLAogICAgICAgICAgICAgICAgICBlbmQgPSBjKDIwMjIsMykpCgpodyA8LSBldHModHJhaW4udHMsCiAgICAgICAgICBtb2RlbCA9ICJaWloiLAogICAgICAgICAgcmVzdHJpY3QgPSBGLAogICAgICAgICAgYWxsb3cubXVsdGlwbGljYXRpdmUudHJlbmQgPSBUKSAjIHNlZSBwbG90IHNlYXNvbmFsIGluIGRlY29tcG9zZQoKaHckbWV0aG9kIAoKIyBJbnRyb2R1Y3RvcnkgVGltZSBTZXJpZXMgV2l0aCBSIC0gUC4gUy4gUC4gQ293cGVyd2FpdCAmIEEuIFYuIE1ldGNhbGZlICgyMDA5KSwgcGFnIDg2CgpgYGAKCmBgYHtyfQojIFdhdmsgVGVzdCBmb3IgVHJlbmQgRGV0ZWN0aW9uCgpub3RyZW5kX3Rlc3QodHJhaW4udHMsCiAgICAgICAgICAgICB0ZXN0ID0gIldBVksiLAogICAgICAgICAgICAgYXIubWV0aG9kID0gImJ1cmciLAogICAgICAgICAgICAgYXIub3JkZXIgPSAyLAogICAgICAgICAgICAgQklDID0gRikgCgojIFdoeSBZdWxlLVdhbGtlciBTaG91bGQgTm90IEJlIFVzZWQgRm9yIEF1dG9yZWdyZXNzaXZlIE1vZGVsbGluZy5wZGYKIyBmdW50aW1lcy5wZGYsIHBhZyAyNQoKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDZ9CiMgSFdFUyAtIEFkZGl0aXZlIEVycm9yCgpodyA8LSBldHModHJhaW4udHMsCiAgICAgICAgICBtb2RlbCA9ICJBTk0iLCAjIE0gc2Vhc29uYWwgaG93IHNob3duIGluIHByZXZpb3VzIHNlY3Rpb24KICAgICAgICAgIHJlc3RyaWN0ID0gRikKCmh3LnByZWQgPC0gZm9yZWNhc3QoaHcsCiAgICAgICAgICAgICAgICAgICAgaCA9IDEyLAogICAgICAgICAgICAgICAgICAgIGxldmVsID0gMCkKClRyYWluX1NldCA8LSB0cmFpbi50cwoKVGVzdF9TZXQgPC0gdGVzdC50cwoKSFdfVHJhaW4gPC0gaHckZml0dGVkCgpIV19UZXN0IDwtIHRzKGMoaHckZml0dGVkWzExMV0sIGh3LnByZWQkbWVhbiksIAogICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDIxLDMpLCAKICAgICAgICAgICAgICAgICAgICBlbmQgPSBjKDIwMjIsMyksIAogICAgICAgICAgICAgICAgICAgIGZyZXF1ZW5jeSA9IDEyKQoKdHNfcGxvdChjYmluZChUcmFpbl9TZXQsVGVzdF9TZXQsSFdfVHJhaW4sSFdfVGVzdCksCiAgICAgICAgc2xpZGVyID0gVCwKICAgICAgICBYZ3JpZCA9IFQsIAogICAgICAgIFlncmlkID0gVCwKICAgICAgICBZdGl0bGUgPSAiVW5pdHMiLAogICAgICAgIFh0aXRsZSA9ICJZZWFyIiwKICAgICAgICB0aXRsZSA9ICJIV0VTIChBLE4sTSkiLAogICAgICAgIHdpZHRoID0gMikKCmBgYAoKYGBge3J9CiMgTWV0cmljcyBmb3IgSFdFUyAtIEFkZGl0aXZlIEVycm9yCgpwcmludChwYXN0ZSgiSFdFUyBNb2RlbCB3aXRoIGFkZGl0aXZlIGVycm9yIC0tPiBBSUM6IiwKICAgICAgICAgICAgcm91bmQoaHckYWljLDIpLAogICAgICAgICAgICAiQklDOiIsCiAgICAgICAgICAgIHJvdW5kKGh3JGJpYywyKSwKICAgICAgICAgICAgIkFJQ2M6IiwKICAgICAgICAgICAgcm91bmQoaHckYWljYywyKSkpCgoKYGBgCgpgYGB7cn0KIyBQbG90IFJlc2lkdWFscyBhbmQgTGp1bmctQm94IFRlc3QgLSBIMDogVGhlIGxldmVsIG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHNlcmllcyBhbmQgaXRzIGxhZyBpcyBlcXVhbCB0byB6ZXJvLCBhbmQgdGhlcmVmb3JlIHRoZSBzZXJpZXMgb2JzZXJ2YXRpb25zIGFyZSBpbmRlcGVuZGVudAoKY2hlY2tyZXNpZHVhbHMoaHcsCiAgICAgICAgICAgICAgIGxhZyA9IDI0KQpgYGAKCmBgYHtyfQojIFNoYXBpcm8tV2lsayBUZXN0IC0gSDA6IE5vcm1hbGx5IERpc3RyaWJ1dGVkCgpzaGFwaXJvLnRlc3QoaHckcmVzaWR1YWxzKQoKYGBgCgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQojIEhXRVMgLSBNdWx0aXBsaWNhdGl2ZSBFcnJvcgoKaHcgPC0gZXRzKHRyYWluLnRzLAogICAgICAgICAgbW9kZWwgPSAiTU5NIiwKICAgICAgICAgIHJlc3RyaWN0ID0gRikgIyBzZWUgcGxvdCBzZWFzb25hbCBpbiBkZWNvbXBvc2UKCmh3LnByZWQgPC0gZm9yZWNhc3QoaHcsCiAgICAgICAgICAgICAgICAgICAgaCA9IDEyLAogICAgICAgICAgICAgICAgICAgIGxldmVsID0gMCkKCkhXX1RyYWluIDwtIGh3JGZpdHRlZAoKSFdfVGVzdCA8LSB0cyhjKGh3JGZpdHRlZFsxMTFdLCBody5wcmVkJG1lYW4pLCAKICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAyMSwzKSwgCiAgICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIyLDMpLCAKICAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoY2JpbmQoVHJhaW5fU2V0LFRlc3RfU2V0LEhXX1RyYWluLEhXX1Rlc3QpLAogICAgICAgIHNsaWRlciA9IFQsCiAgICAgICAgWGdyaWQgPSBULCAKICAgICAgICBZZ3JpZCA9IFQsCiAgICAgICAgWXRpdGxlID0gIlVuaXRzIiwKICAgICAgICBYdGl0bGUgPSAiWWVhciIsCiAgICAgICAgdGl0bGUgPSAiSFdFUyAoTSxOLE0pIiwKICAgICAgICB3aWR0aCA9IDIpCgpgYGAKCmBgYHtyfQojIE1ldHJpY3MgZm9yIEhXRVMgLSBNdWx0aXBsaWNhdGl2ZSBFcnJvcgoKcHJpbnQocGFzdGUoIkhXRVMgTW9kZWwgd2l0aCBtdWx0aXBsaWNhdGl2ZSBlcnJvciAtLT4gQUlDOiIsCiAgICAgICAgICAgIHJvdW5kKGh3JGFpYywyKSwKICAgICAgICAgICAgIkJJQzoiLAogICAgICAgICAgICByb3VuZChodyRiaWMsMiksCiAgICAgICAgICAgICJBSUNjOiIsCiAgICAgICAgICAgIHJvdW5kKGh3JGFpY2MsMikpKQoKYGBgCgpgYGB7cn0KIyBQbG90IFJlc2lkdWFscyBhbmQgTGp1bmctQm94IFRlc3QgLSBIMDogVGhlIGxldmVsIG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHNlcmllcyBhbmQgaXRzIGxhZyBpcyBlcXVhbCB0byB6ZXJvLCBhbmQgdGhlcmVmb3JlIHRoZSBzZXJpZXMgb2JzZXJ2YXRpb25zIGFyZSBpbmRlcGVuZGVudAoKY2hlY2tyZXNpZHVhbHMoaHcsCiAgICAgICAgICAgICAgIGxhZyA9IDI0KQoKYGBgCgpgYGB7cn0KIyBTaGFwaXJvLVdpbGsgVGVzdCAtIEgwOiBOb3JtYWxseSBEaXN0cmlidXRlZAoKc2hhcGlyby50ZXN0KGh3JHJlc2lkdWFscykKCmBgYAoKIyMjIyBTQVJJTUEgKFNlYXNvbmFsIEF1dG9yZWdyZXNzaXZlIEludGVncmF0ZWQgTW92aW5nIEF2ZXJhZ2UpCgpgYGB7cn0KIyBTQVJJTUEgTW9kZWxzCgp0cmFpbi50cyA8LSB3aW5kb3coSVRBLCAKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDEyLDEpLAogICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDMpKQp2YWxpZC50cyA8LSB3aW5kb3coSVRBLCAKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDIxLDMpLCAKICAgICAgICAgICAgICAgICAgIGVuZCA9IGMoMjAyMSw5KSkKdGVzdC50cyA8LSB3aW5kb3coSVRBLCAKICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjKDIwMjEsOSksIAogICAgICAgICAgICAgICAgICBlbmQgPSBjKDIwMjIsMykpCgpzYXJpbWEgPC0gYXV0by5hcmltYSh0cmFpbi50cywgCiAgICAgICAgICAgICAgICAgICAgIHNlYXNvbmFsID0gVCkgIyAoMCwxLDApKDIsMCwwKQoKcHJpbnQocGFzdGUoIkF1dG8gU0FSSU1BIE1vZGVsIC0tPiBBSUM6IiwKICAgICAgICAgICAgcm91bmQoc2FyaW1hJGFpYywyKSwKICAgICAgICAgICAgIkJJQzoiLAogICAgICAgICAgICByb3VuZChzYXJpbWEkYmljLDIpKSkKCnNhcmltYSA8LSBBcmltYSh0cmFpbi50cywgCiAgICAgICAgICAgICAgICBvcmRlciA9IGMoMiwxLDMpLCAKICAgICAgICAgICAgICAgIHNlYXNvbmFsID0gYygxLDEsMSkpCgpwcmludChwYXN0ZSgiU0FSSU1BIE1vZGVsIGJhc2VkIG9uIHRoZW9yeSAtLT4gQUlDOiIsCiAgICAgICAgICAgIHJvdW5kKEFJQyhzYXJpbWEpLDIpLAogICAgICAgICAgICAiQklDOiIsCiAgICAgICAgICAgIHJvdW5kKEJJQyhzYXJpbWEpLDIpKSkKCnNhcmltYSA8LSBBcmltYSh0cmFpbi50cywgCiAgICAgICAgICAgICAgICBvcmRlciA9IGMoMCwxLDApLAogICAgICAgICAgICAgICAgc2Vhc29uYWwgPSBjKDEsMSwxKSkKCnByaW50KHBhc3RlKCJTQVJJTUEgTW9kZWwgbmVhciB0byBhdXRvLmFyaW1hIC0tPiBBSUM6IiwKICAgICAgICAgICAgcm91bmQoQUlDKHNhcmltYSksMiksCiAgICAgICAgICAgICJCSUM6IiwKICAgICAgICAgICAgcm91bmQoQklDKHNhcmltYSksMikpKQoKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDZ9CiMgQXV0byBTQVJJTUEgTW9kZWwKCnNhcmltYSA8LSBhdXRvLmFyaW1hKHRyYWluLnRzLCAKICAgICAgICAgICAgICAgICAgICAgc2Vhc29uYWwgPSBUKQoKc2FyaW1hLnByZWQgPC0gZm9yZWNhc3Qoc2FyaW1hLAogICAgICAgICAgICAgICAgICAgICAgICAgIGggPSA2LAogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsID0gMCkKClRyYWluX1NldCA8LSB0cmFpbi50cwoKVmFsaWRhdGlvbl9TZXQgPC0gdmFsaWQudHMKCkF1dG9fU0FSSU1BX1RyYWluIDwtIHNhcmltYS5wcmVkJGZpdHRlZAoKQXV0b19TQVJJTUFfVmFsaWRhdGlvbiA8LSB0cyhjKHNhcmltYS5wcmVkJGZpdHRlZFsxMTFdLCBzYXJpbWEucHJlZCRtZWFuKSwgCiAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjKDIwMjEsMyksIAogICAgICAgICAgICAgICAgICAgIGVuZCA9IGMoMjAyMSw5KSwgCiAgICAgICAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCgp0c19wbG90KGNiaW5kKFRyYWluX1NldCxWYWxpZGF0aW9uX1NldCxBdXRvX1NBUklNQV9UcmFpbixBdXRvX1NBUklNQV9WYWxpZGF0aW9uKSwKICAgICAgICBzbGlkZXIgPSBULAogICAgICAgIFhncmlkID0gVCwgCiAgICAgICAgWWdyaWQgPSBULAogICAgICAgIFl0aXRsZSA9ICJVbml0cyIsCiAgICAgICAgWHRpdGxlID0gIlllYXIiLAogICAgICAgIHRpdGxlID0gIkF1dG8gU0FSSU1BKDAsMSwwKXgoMiwwLDApIiwKICAgICAgICB3aWR0aCA9IDIpCgpgYGAKCmBgYHtyfQojIFBsb3QgUmVzaWR1YWxzIGFuZCBManVuZy1Cb3ggVGVzdCAtIEgwOiBUaGUgbGV2ZWwgb2YgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2VyaWVzIGFuZCBpdHMgbGFnIGlzIGVxdWFsIHRvIHplcm8sIGFuZCB0aGVyZWZvcmUgdGhlIHNlcmllcyBvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50CgpjaGVja3Jlc2lkdWFscyhzYXJpbWEsCiAgICAgICAgICAgICAgIGxhZyA9IDI0KQoKYGBgCgpgYGB7cn0KIyBTaGFwaXJvLVdpbGsgVGVzdCAtIEgwOiBOb3JtYWxseSBEaXN0cmlidXRlZAoKc2hhcGlyby50ZXN0KHNhcmltYSRyZXNpZHVhbHMpCgpgYGAKCmBgYHtyfQojIFNjb3JpbmcgQXV0byBTQVJJTUEgTW9kZWwKCmFjIDwtIGFjY3VyYWN5KHNhcmltYS5wcmVkLCB2YWxpZC50cykKCnJvdy5uYW1lcyhhYylbMl0gPC0gIlZhbGlkYXRpb24gU2V0IgoKYWMKCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQojIFNBUklNQSBNb2RlbCBiYXNlZCBvbiBUaGVvcnkKCnNhcmltYSA8LSBBcmltYSh0cmFpbi50cywgCiAgICAgICAgICAgICAgICBvcmRlciA9IGMoMiwxLDMpLCAKICAgICAgICAgICAgICAgIHNlYXNvbmFsID0gYygxLDEsMSkpCgpzYXJpbWEucHJlZCA8LSBmb3JlY2FzdChzYXJpbWEsCiAgICAgICAgICAgICAgICAgICAgICAgIGggPSA2LAogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbCA9IDApCgpUcmFpbl9TZXQgPC0gdHJhaW4udHMKClZhbGlkYXRpb25fU2V0IDwtIHZhbGlkLnRzCgpTQVJJTUFfVGhlb3J5X1RyYWluIDwtIHNhcmltYS5wcmVkJGZpdHRlZAoKU0FSSU1BX1RoZW9yeV9WYWxpZGF0aW9uIDwtIHRzKGMoc2FyaW1hLnByZWQkZml0dGVkWzExMV0sIHNhcmltYS5wcmVkJG1lYW4pLCAKICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAyMSwzKSwgCiAgICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDkpLCAKICAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoY2JpbmQoVHJhaW5fU2V0LFZhbGlkYXRpb25fU2V0LFNBUklNQV9UaGVvcnlfVHJhaW4sU0FSSU1BX1RoZW9yeV9WYWxpZGF0aW9uKSwKICAgICAgICBzbGlkZXIgPSBULAogICAgICAgIFhncmlkID0gVCwgCiAgICAgICAgWWdyaWQgPSBULAogICAgICAgIFl0aXRsZSA9ICJVbml0cyIsCiAgICAgICAgWHRpdGxlID0gIlllYXIiLAogICAgICAgIHRpdGxlID0gIlNBUklNQSgyLDEsMyl4KDEsMSwxKSIsCiAgICAgICAgd2lkdGggPSAyKQoKYGBgCgpgYGB7cn0KIyBQbG90IFJlc2lkdWFscyBhbmQgTGp1bmctQm94IFRlc3QgLSBIMDogVGhlIGxldmVsIG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHNlcmllcyBhbmQgaXRzIGxhZyBpcyBlcXVhbCB0byB6ZXJvLCBhbmQgdGhlcmVmb3JlIHRoZSBzZXJpZXMgb2JzZXJ2YXRpb25zIGFyZSBpbmRlcGVuZGVudAoKY2hlY2tyZXNpZHVhbHMoc2FyaW1hLAogICAgICAgICAgICAgICBsYWcgPSAyNCkKCmBgYAoKYGBge3J9CiMgU2hhcGlyby1XaWxrIFRlc3QgLSBIMDogTm9ybWFsbHkgRGlzdHJpYnV0ZWQKCnNoYXBpcm8udGVzdChzYXJpbWEkcmVzaWR1YWxzKQoKYGBgCgpgYGB7cn0KIyBTY29yaW5nIFNBUklNQSBNb2RlbCBiYXNlZCBvbiBUaGVvcnkKCmFjIDwtIGFjY3VyYWN5KHNhcmltYS5wcmVkLCB2YWxpZC50cykKCnJvdy5uYW1lcyhhYylbMl0gPC0gIlZhbGlkYXRpb24gU2V0IgoKYWMKCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQojIFNBUklNQSBNb2RlbCBuZWFyIHRvIEF1dG8KCnNhcmltYSA8LSBBcmltYSh0cmFpbi50cywgCiAgICAgICAgICAgICAgICBvcmRlciA9IGMoMCwxLDApLAogICAgICAgICAgICAgICAgc2Vhc29uYWwgPSBjKDEsMSwxKSkKCnNhcmltYS5wcmVkIDwtIGZvcmVjYXN0KHNhcmltYSwKICAgICAgICAgICAgICAgICAgICAgICAgICBoID0gNiwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbCA9IDApCgpUcmFpbl9TZXQgPC0gdHJhaW4udHMKClZhbGlkYXRpb25fU2V0IDwtIHZhbGlkLnRzCgpTQVJJTUFfTmVhcl9UcmFpbiA8LSBzYXJpbWEucHJlZCRmaXR0ZWQKClNBUklNQV9OZWFyX1ZhbGlkYXRpb24gPC0gdHMoYyhzYXJpbWEucHJlZCRmaXR0ZWRbMTExXSwgc2FyaW1hLnByZWQkbWVhbiksIAogICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDIxLDMpLCAKICAgICAgICAgICAgICAgICAgICBlbmQgPSBjKDIwMjEsOSksIAogICAgICAgICAgICAgICAgICAgIGZyZXF1ZW5jeSA9IDEyKQoKdHNfcGxvdChjYmluZChUcmFpbl9TZXQsVmFsaWRhdGlvbl9TZXQsU0FSSU1BX05lYXJfVHJhaW4sU0FSSU1BX05lYXJfVmFsaWRhdGlvbiksCiAgICAgICAgc2xpZGVyID0gVCwKICAgICAgICBYZ3JpZCA9IFQsIAogICAgICAgIFlncmlkID0gVCwKICAgICAgICBZdGl0bGUgPSAiVW5pdHMiLAogICAgICAgIFh0aXRsZSA9ICJZZWFyIiwKICAgICAgICB0aXRsZSA9ICJTQVJJTUEoMCwxLDApeCgxLDEsMSkiLAogICAgICAgIHdpZHRoID0gMikKCmBgYAoKYGBge3J9CiMgUGxvdCBSZXNpZHVhbHMgYW5kIExqdW5nLUJveCBUZXN0IC0gSDA6IFRoZSBsZXZlbCBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBzZXJpZXMgYW5kIGl0cyBsYWcgaXMgZXF1YWwgdG8gemVybywgYW5kIHRoZXJlZm9yZSB0aGUgc2VyaWVzIG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQKCmNoZWNrcmVzaWR1YWxzKHNhcmltYSwKICAgICAgICAgICAgICAgbGFnID0gMjQpCgpgYGAKCmBgYHtyfQojIFNoYXBpcm8tV2lsayBUZXN0IC0gSDA6IE5vcm1hbGx5IERpc3RyaWJ1dGVkCgpzaGFwaXJvLnRlc3Qoc2FyaW1hJHJlc2lkdWFscykKCmBgYAoKYGBge3J9CiMgU2NvcmluZyBTQVJJTUEgTW9kZWwgTmVhciB0byBBdXRvCgphYyA8LSBhY2N1cmFjeShzYXJpbWEucHJlZCwgdmFsaWQudHMpCgpyb3cubmFtZXMoYWMpWzJdIDwtICJWYWxpZGF0aW9uIFNldCIKCmFjCgpgYGAKCiMjIyMgU0FSSU1BWCAoU2Vhc29uYWwgQXV0b3JlZ3Jlc3NpdmUgSW50ZWdyYXRlZCBNb3ZpbmcgQXZlcmFnZSBFeG9nZW5vdXMpCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDV9CiMgTG9hZCBEYXRhIGFuZCBNSUIgVGltZSBTZXJpZXMKCk1JQiA8LSByZWFkLmNzdignL1VzZXJzL2xvcmVuem9sZW9uaS9EZXNrdG9wL01hdGVyaWFsZSBQZXJzb25hbGUvUHJvamVjdHMvVGltZSBTZXJpZXMgQW5hbHlzaXMgLSBDYXIgU2FsZXMgSW4gSXRhbHkvZGF0YS9NSUJfMTItMjIuY3N2JywKICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgc2VwID0gIjsiLAogICAgICAgICAgICAgICAgICBkZWMgPSAiLiIpCgpNSUIgPC0gdHMoTUlCJENMT1NFLCBzdGFydCA9IGMoMjAxMiwxKSwgZnJlcXVlbmN5ID0gMTIpCgp0c19wbG90KE1JQiwKICAgICBYZ3JpZCA9IFQsIAogICAgIFlncmlkID0gVCwKICAgICBZdGl0bGUgPSAiVmFsdWUiLAogICAgIFh0aXRsZSA9ICJZZWFyIiwKICAgICB0aXRsZSA9ICJUaW1lIFNlcmllcyAtIE1JQiIsCiAgICAgd2lkdGggPSAyLAogICAgIGNvbG9yID0gImJsYWNrIikKCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQoKIyBTQVJJTUFYIHdpdGggTUlCCgp0cmFpbi5NSUIgPC0gd2luZG93KE1JQiwgCiAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAxMiwxKSwKICAgICAgICAgICAgICAgICAgIGVuZCA9IGMoMjAyMSwzKSkKdmFsaWQuTUlCIDwtIHdpbmRvdyhNSUIsIAogICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjKDIwMjEsMyksIAogICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDkpKQoKc2FyaW1heCA8LSBBcmltYSh0cmFpbi50cywgCiAgICAgICAgICAgICAgICBvcmRlciA9IGMoMiwxLDMpLAogICAgICAgICAgICAgICAgc2Vhc29uYWwgPSBsaXN0KG9yZGVyID0gYygxLDEsMSksIHBlcmlvZCA9IDEyKSwKICAgICAgICAgICAgICAgIHhyZWc9dHJhaW4uTUlCKQoKc2FyaW1heC5wcmVkIDwtIGZvcmVjYXN0KHNhcmltYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaCA9IDYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWwgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIHhyZWc9dmFsaWQuTUlCKQoKVHJhaW5fU2V0IDwtIHRyYWluLnRzCgpWYWxpZGF0aW9uX1NldCA8LSB2YWxpZC50cwoKU0FSSU1BWF9NSUJfVHJhaW4gPC0gc2FyaW1heC5wcmVkJGZpdHRlZAoKU0FSSU1BWF9NSUJfVmFsaWRhdGlvbiA8LSB0cyhjKHNhcmltYXgucHJlZCRmaXR0ZWRbMTExXSwgc2FyaW1heC5wcmVkJG1lYW4pLCAKICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAyMSwzKSwgCiAgICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDkpLCAKICAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoY2JpbmQoVHJhaW5fU2V0LFZhbGlkYXRpb25fU2V0LFNBUklNQVhfTUlCX1RyYWluLFNBUklNQVhfTUlCX1ZhbGlkYXRpb24pLAogICAgICAgIHNsaWRlciA9IFQsCiAgICAgICAgWGdyaWQgPSBULCAKICAgICAgICBZZ3JpZCA9IFQsCiAgICAgICAgWXRpdGxlID0gIlVuaXRzIiwKICAgICAgICBYdGl0bGUgPSAiWWVhciIsCiAgICAgICAgdGl0bGUgPSAiU0FSSU1BWCgyLDEsMyl4KDEsMSwxKSAtIE1JQiIsCiAgICAgICAgd2lkdGggPSAyKQoKYGBgCmBgYHtyfQojIE1ldHJpY3MgU0FSSU1BWCBNb2RlbCB3aXRoIE1JQgoKcHJpbnQocGFzdGUoIlNBUklNQVggTW9kZWwgd2l0aCBNSUIgYXMgcmVncmVzc29yIC0tPiBBSUM6IiwKICAgICAgICAgICAgcm91bmQoQUlDKHNhcmltYXgpLDIpLAogICAgICAgICAgICAiQklDOiIsCiAgICAgICAgICAgIHJvdW5kKEJJQyhzYXJpbWF4KSwyKSkpCgpgYGAKCmBgYHtyfQojIFBsb3QgUmVzaWR1YWxzIGFuZCBManVuZy1Cb3ggVGVzdCAtIEgwOiBUaGUgbGV2ZWwgb2YgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2VyaWVzIGFuZCBpdHMgbGFnIGlzIGVxdWFsIHRvIHplcm8sIGFuZCB0aGVyZWZvcmUgdGhlIHNlcmllcyBvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50CgpjaGVja3Jlc2lkdWFscyhzYXJpbWF4LAogICAgICAgICAgICAgICBsYWcgPSAyNCkKCmBgYAoKYGBge3J9CiMgU2hhcGlyby1XaWxrIFRlc3QgLSBIMDogTm9ybWFsbHkgRGlzdHJpYnV0ZWQKCnNoYXBpcm8udGVzdChzYXJpbWF4JHJlc2lkdWFscykKCmBgYAoKYGBge3J9CiMgU2NvcmluZyBTQVJJTUFYIE1vZGVsIHdpdGggTUlCCgphYyA8LSBhY2N1cmFjeShzYXJpbWF4LnByZWQsIHZhbGlkLnRzKQoKcm93Lm5hbWVzKGFjKVsyXSA8LSAiVmFsaWRhdGlvbiBTZXQiCgphYwoKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDV9CiMgTG9hZCBEYXRhIGFuZCBVbmVtcGxveW1lbnQgUmF0ZSBUaW1lIFNlcmllcwoKVW5yIDwtIHJlYWQuY3N2KCcvVXNlcnMvbG9yZW56b2xlb25pL0Rlc2t0b3AvTWF0ZXJpYWxlIFBlcnNvbmFsZS9Qcm9qZWN0cy9UaW1lIFNlcmllcyBBbmFseXNpcyAtIENhciBTYWxlcyBJbiBJdGFseS9kYXRhL1VuZW1wbG95bWVudF9SYXRlXzEyLTIyLmNzdicsCiAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIHNlcCA9ICI7IiwKICAgICAgICAgICAgICAgICAgZGVjID0gIi4iKQoKVW5yIDwtIHRzKFVuciRUYXgsIHN0YXJ0ID0gYygyMDEyLDEpLCBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoVW5yLAogICAgIFhncmlkID0gVCwgCiAgICAgWWdyaWQgPSBULAogICAgIFl0aXRsZSA9ICJWYWx1ZSIsCiAgICAgWHRpdGxlID0gIlllYXIiLAogICAgIHRpdGxlID0gIlRpbWUgU2VyaWVzIC0gVW5lbXBsb3ltZW50IFJhdGUiLAogICAgIHdpZHRoID0gMiwKICAgICBjb2xvciA9ICJibGFjayIpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNn0KCiMgU0FSSU1BWCB3aXRoIFVuZW1wbG95bWVudCBSYXRlCgp0cmFpbi5VbnIgPC0gd2luZG93KFVuciwgCiAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAxMiwxKSwKICAgICAgICAgICAgICAgICAgIGVuZCA9IGMoMjAyMSwzKSkKdmFsaWQuVW5yIDwtIHdpbmRvdyhVbnIsIAogICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjKDIwMjEsMyksIAogICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDkpKQoKc2FyaW1heCA8LSBBcmltYSh0cmFpbi50cywgCiAgICAgICAgICAgICAgICBvcmRlciA9IGMoMiwxLDMpLAogICAgICAgICAgICAgICAgc2Vhc29uYWwgPSBsaXN0KG9yZGVyID0gYygxLDEsMSksIHBlcmlvZCA9IDEyKSwKICAgICAgICAgICAgICAgIHhyZWc9dHJhaW4uVW5yKQoKc2FyaW1heC5wcmVkIDwtIGZvcmVjYXN0KHNhcmltYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaCA9IDYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWwgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIHhyZWc9dmFsaWQuVW5yKQoKVHJhaW5fU2V0IDwtIHRyYWluLnRzCgpWYWxpZGF0aW9uX1NldCA8LSB2YWxpZC50cwoKU0FSSU1BWF9VbnJfVHJhaW4gPC0gc2FyaW1heC5wcmVkJGZpdHRlZAoKU0FSSU1BWF9VbnJfVmFsaWRhdGlvbiA8LSB0cyhjKHNhcmltYXgucHJlZCRmaXR0ZWRbMTExXSwgc2FyaW1heC5wcmVkJG1lYW4pLCAKICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAyMSwzKSwgCiAgICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDkpLCAKICAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoY2JpbmQoVHJhaW5fU2V0LFZhbGlkYXRpb25fU2V0LFNBUklNQVhfVW5yX1RyYWluLFNBUklNQVhfVW5yX1ZhbGlkYXRpb24pLAogICAgICAgIHNsaWRlciA9IFQsCiAgICAgICAgWGdyaWQgPSBULCAKICAgICAgICBZZ3JpZCA9IFQsCiAgICAgICAgWXRpdGxlID0gIlVuaXRzIiwKICAgICAgICBYdGl0bGUgPSAiWWVhciIsCiAgICAgICAgdGl0bGUgPSAiU0FSSU1BWCgyLDEsMyl4KDEsMSwxKSAtIFVuZW1wbG95bWVudCBSYXRlIiwKICAgICAgICB3aWR0aCA9IDIpCgpgYGAKCmBgYHtyfQojIE1ldHJpY3MgU0FSSU1BWCBNb2RlbCB3aXRoIFVucgoKcHJpbnQocGFzdGUoIlNBUklNQVggTW9kZWwgd2l0aCBVbnIgYXMgcmVncmVzc29yIC0tPiBBSUM6IiwKICAgICAgICAgICAgcm91bmQoQUlDKHNhcmltYXgpLDIpLAogICAgICAgICAgICAiQklDOiIsCiAgICAgICAgICAgIHJvdW5kKEJJQyhzYXJpbWF4KSwyKSkpCgpgYGAKCmBgYHtyfQojIFBsb3QgUmVzaWR1YWxzIGFuZCBManVuZy1Cb3ggVGVzdCAtIEgwOiBUaGUgbGV2ZWwgb2YgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2VyaWVzIGFuZCBpdHMgbGFnIGlzIGVxdWFsIHRvIHplcm8sIGFuZCB0aGVyZWZvcmUgdGhlIHNlcmllcyBvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50CgpjaGVja3Jlc2lkdWFscyhzYXJpbWF4LAogICAgICAgICAgICAgICBsYWcgPSAyNCkKCmBgYAoKYGBge3J9CiMgU2hhcGlyby1XaWxrIFRlc3QgLSBIMDogTm9ybWFsbHkgRGlzdHJpYnV0ZWQKCnNoYXBpcm8udGVzdChzYXJpbWF4JHJlc2lkdWFscykKCmBgYAoKYGBge3J9CiMgU2NvcmluZyBTQVJJTUFYIE1vZGVsIHdpdGggVW5lbXBsb3ltZW50IFJhdGUKCmFjIDwtIGFjY3VyYWN5KHNhcmltYXgucHJlZCwgdmFsaWQudHMpCgpyb3cubmFtZXMoYWMpWzJdIDwtICJWYWxpZGF0aW9uIFNldCIKCmFjCgpgYGAKCiMjIFRJTUUgU0VSSUVTIEZPUkVDQVNUSU5HCgpgYGB7cn0KIyBUcmFpbiBhbmQgVGVzdCBTZXRzCgp0cmFpbi50cyA8LSB3aW5kb3coSVRBLCAKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDEyLDEpLAogICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDkpKQoKdGVzdC50cyA8LSB3aW5kb3coSVRBLCAKICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjKDIwMjEsOSksIAogICAgICAgICAgICAgICAgICBlbmQgPSBjKDIwMjIsMykpCgpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNn0KIyBTQVJJTUEgTW9kZWwgYmFzZWQgb24gVGhlb3J5CgpzYXJpbWEgPC0gQXJpbWEodHJhaW4udHMsIAogICAgICAgICAgICAgICAgb3JkZXIgPSBjKDIsMSwzKSwgCiAgICAgICAgICAgICAgICBzZWFzb25hbCA9IGMoMSwxLDEpKQoKc2FyaW1hLnByZWQgPC0gZm9yZWNhc3Qoc2FyaW1hLAogICAgICAgICAgICAgICAgICAgICAgICBoID0gNiwKICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWwgPSAwKQoKVHJhaW5fU2V0IDwtIHRyYWluLnRzCgpUZXN0X1NldCA8LSB0ZXN0LnRzCgpTQVJJTUFfVGhlb3J5X1RyYWluIDwtIHNhcmltYS5wcmVkJGZpdHRlZAoKU0FSSU1BX1RoZW9yeV9UZXN0IDwtIHRzKGMoc2FyaW1hLnByZWQkZml0dGVkWzExN10sIHNhcmltYS5wcmVkJG1lYW4pLCAKICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAyMSw5KSwgCiAgICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIyLDMpLCAKICAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoY2JpbmQoVHJhaW5fU2V0LFRlc3RfU2V0LFNBUklNQV9UaGVvcnlfVHJhaW4sU0FSSU1BX1RoZW9yeV9UZXN0KSwKICAgICAgICBzbGlkZXIgPSBULAogICAgICAgIFhncmlkID0gVCwgCiAgICAgICAgWWdyaWQgPSBULAogICAgICAgIFl0aXRsZSA9ICJVbml0cyIsCiAgICAgICAgWHRpdGxlID0gIlllYXIiLAogICAgICAgIHRpdGxlID0gIlNBUklNQSgyLDEsMyl4KDEsMSwxKSIsCiAgICAgICAgd2lkdGggPSAyKQoKYGBgCgpgYGB7cn0KIyBNZXRyaWNzIGZvciBTQVJJTUEgTW9kZWwgYmFzZWQgb24gdGhlb3J5CgpwcmludChwYXN0ZSgiU0FSSU1BIE1vZGVsIGJhc2VkIG9uIHRoZW9yeSAtLT4gQUlDOiIsCiAgICAgICAgICAgIHJvdW5kKEFJQyhzYXJpbWEpLDIpLAogICAgICAgICAgICAiQklDOiIsCiAgICAgICAgICAgIHJvdW5kKEJJQyhzYXJpbWEpLDIpKSkKCmBgYAoKYGBge3J9CiMgUGxvdCBSZXNpZHVhbHMgYW5kIExqdW5nLUJveCBUZXN0IC0gSDA6IFRoZSBsZXZlbCBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBzZXJpZXMgYW5kIGl0cyBsYWcgaXMgZXF1YWwgdG8gemVybywgYW5kIHRoZXJlZm9yZSB0aGUgc2VyaWVzIG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQKCmNoZWNrcmVzaWR1YWxzKHNhcmltYSwKICAgICAgICAgICAgICAgbGFnID0gMjQpCgpgYGAKCmBgYHtyfQojIFNoYXBpcm8tV2lsayBUZXN0IC0gSDA6IE5vcm1hbGx5IERpc3RyaWJ1dGVkCgpzaGFwaXJvLnRlc3Qoc2FyaW1hJHJlc2lkdWFscykKCmBgYAoKYGBge3J9CiMgU2NvcmluZyBTQVJJTUEgTW9kZWwgYmFzZWQgb24gVGhlb3J5CgphY2N1cmFjeShzYXJpbWEucHJlZCwgdGVzdC50cykKCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQoKIyBTQVJJTUFYIHdpdGggVW5lbXBsb3ltZW50IFJhdGUKCnRyYWluLlVuciA8LSB3aW5kb3coVW5yLCAKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDEyLDEpLAogICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIxLDkpKQp0ZXN0LlVuciA8LSB3aW5kb3coVW5yLCAKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDIxLDkpLCAKICAgICAgICAgICAgICAgICAgIGVuZCA9IGMoMjAyMiwyKSkKCnNhcmltYXggPC0gQXJpbWEodHJhaW4udHMsIAogICAgICAgICAgICAgICAgb3JkZXIgPSBjKDIsMSwzKSwKICAgICAgICAgICAgICAgIHNlYXNvbmFsID0gbGlzdChvcmRlciA9IGMoMSwxLDEpLCBwZXJpb2QgPSAxMiksCiAgICAgICAgICAgICAgICB4cmVnPXRyYWluLlVucikKCnNhcmltYXgucHJlZCA8LSBmb3JlY2FzdChzYXJpbWF4LAogICAgICAgICAgICAgICAgICAgICAgICAgIGggPSA2LAogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICB4cmVnPXRlc3QuVW5yKQoKU0FSSU1BWF9VbnJfVHJhaW4gPC0gc2FyaW1heC5wcmVkJGZpdHRlZAoKU0FSSU1BWF9VbnJfVGVzdCA8LSB0cyhjKHNhcmltYXgucHJlZCRmaXR0ZWRbMTE3XSwgc2FyaW1heC5wcmVkJG1lYW4pLCAKICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAyMSw5KSwgCiAgICAgICAgICAgICAgICAgICAgZW5kID0gYygyMDIyLDMpLCAKICAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKCnRzX3Bsb3QoY2JpbmQoVHJhaW5fU2V0LFRlc3RfU2V0LFNBUklNQVhfVW5yX1RyYWluLFNBUklNQVhfVW5yX1Rlc3QpLAogICAgICAgIHNsaWRlciA9IFQsCiAgICAgICAgWGdyaWQgPSBULCAKICAgICAgICBZZ3JpZCA9IFQsCiAgICAgICAgWXRpdGxlID0gIlVuaXRzIiwKICAgICAgICBYdGl0bGUgPSAiWWVhciIsCiAgICAgICAgdGl0bGUgPSAiU0FSSU1BWCgyLDEsMyl4KDEsMSwxKSAtIFVuZW1wbG95bWVudCBSYXRlIiwKICAgICAgICB3aWR0aCA9IDIpCgpgYGAKCmBgYHtyfQojIE1ldHJpY3MgU0FSSU1BWCBNb2RlbCB3aXRoIFVucgoKcHJpbnQocGFzdGUoIlNBUklNQVggTW9kZWwgd2l0aCBVbnIgYXMgcmVncmVzc29yIC0tPiBBSUM6IiwKICAgICAgICAgICAgcm91bmQoQUlDKHNhcmltYXgpLDIpLAogICAgICAgICAgICAiQklDOiIsCiAgICAgICAgICAgIHJvdW5kKEJJQyhzYXJpbWF4KSwyKSkpCgpgYGAKCmBgYHtyfQojIFBsb3QgUmVzaWR1YWxzIGFuZCBManVuZy1Cb3ggVGVzdCAtIEgwOiBUaGUgbGV2ZWwgb2YgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2VyaWVzIGFuZCBpdHMgbGFnIGlzIGVxdWFsIHRvIHplcm8sIGFuZCB0aGVyZWZvcmUgdGhlIHNlcmllcyBvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50CgpjaGVja3Jlc2lkdWFscyhzYXJpbWF4LAogICAgICAgICAgICAgICBsYWcgPSAyNCkKCmBgYAoKYGBge3J9CiMgU2hhcGlyby1XaWxrIFRlc3QgLSBIMDogTm9ybWFsbHkgRGlzdHJpYnV0ZWQKCnNoYXBpcm8udGVzdChzYXJpbWF4JHJlc2lkdWFscykKCmBgYAoKYGBge3J9CiMgU2NvcmluZyBTQVJJTUFYIHdpdGggVW5lbXBsb3ltZW50IFJhdGUKCmFjY3VyYWN5KHNhcmltYXgucHJlZCwgdGVzdC50cykKCmBgYAoKYGBge3J9CiMgRGVsZXRlIGxhc3QgdmFyaWFibGVzCgpybShzZWFzb25hbF90ZXN0LAogICBjdl9kLAogICBjdl9xLAogICBNSUIsCiAgIFRlc3RfU2V0LAogICB0ZXN0LnRzLAogICBUcmFpbl9TZXQsCiAgIHRyYWluLnRzLAogICB2YWxpZC50cywKICAgVmFsaWRhdGlvbl9TZXQsCiAgIElUQS5kZWMsCiAgIHQsCiAgIFNBUklNQVhfVW5yX1RyYWluLAogICBTQVJJTUFYX1Vucl9UZXN0LAogICB0cmFpbi5VbnIsCiAgIHRlc3QuVW5yLAogICB2YWxpZC5VbnIsCiAgIFNBUklNQV9UaGVvcnlfVHJhaW4sCiAgIFNBUklNQV9UaGVvcnlfVmFsaWRhdGlvbiwKICAgU0FSSU1BX1RoZW9yeV9UZXN0LAogICBTQVJJTUFYX1Vucl9WYWxpZGF0aW9uLAogICBTQVJJTUFYX01JQl9UcmFpbiwKICAgU0FSSU1BWF9NSUJfVmFsaWRhdGlvbiwKICAgdHJhaW4uTUlCLAogICB2YWxpZC5NSUIsCiAgIEF1dG9fU0FSSU1BX1RyYWluLAogICBBdXRvX1NBUklNQV9WYWxpZGF0aW9uLAogICBTQVJJTUFfTmVhcl9UcmFpbiwKICAgU0FSSU1BX05lYXJfVmFsaWRhdGlvbiwKICAgaHcsCiAgIGh3LnByZWQsCiAgIEhXX1RyYWluLAogICBIV19UZXN0LAogICBhYywKICAgaSwKICAgaywKICAgRCwKICAgUSwKICAgcGFjLAogICBteV9wbG90LmRlY29tcG9zZWQudHMsCiAgIG15X3Bsb3QubGFncy50cywKICAgSVRBX2RldCwKICAgSVRBX2RlcykKCmBgYAoKCg==